// 确保只有一处类定义
#ifndef MYMQTT_H
#define MYMQTT_H
#include "header.cpp"
#include "config.cpp"
class MyMqtt
// 父类（基类）
{
public:
    // MyMqtt() {}
    int tickerCount;    // Ticker计数用变量
    int pin = 0;  // 设置一个变量代表控制继电器开关的GPIO
    // int LED_BUILTIN = 2; led灯开关
    //  JSON 对象 wifi配置
    JSONVar wifiConf;
    // json 对象 mqtt配置
    JSONVar mqttConf;
    // // 定时器
    // Ticker ticker;

    Config config;
    // // WiFi and MQTT client initialization
    BearSSL::WiFiClientSecure espClient;
    PubSubClient mqtt_client;
    // 使用std::function定义回调函数类型
    using Callback = std::function<void(int state)>;
    MyMqtt(): mqtt_client(espClient),config(){

    };
// Function declarations
    void setCallback(Callback cb){
        callback_=cb;
    }
    // 实现使用回调函数的函数
    void doCallback(int state) {
        Serial.print("MQTT Callback:"); //打印esp8266的IP地址
        Serial.print(state); //打印esp8266的IP地址
        if (callback_) {
              callback_(state);
        }
    }

    // wifi 账号密码
    void initWifiConfig() {
      JSONVar conf= config.getWifiConf();
      if (conf) {
      wifiConf=conf;
        return;
      }
      wifiConf["user"] = "hy1";
      wifiConf["password"] = "13363641456";
    }
    // mqtt 配置
    void initMqttConfig() {
      JSONVar conf= config.getMqttConf();
      if (conf) {
        mqttConf=conf;
        String jsonString = JSON.stringify(conf);
        Serial.println(jsonString);  //打印esp8266的IP地址
        return;
      }
    //   mqttConf["mqtt_port"] = 8883;
    //   // 去 EMQX 官网注册账号可以申请免费额度
    //   mqttConf["mqtt_broker"] = "n9a7eff0.ala.cn-hangzhou.emqxsl.cn";
    //   // 订阅主题
    //   mqttConf["mqtt_subscribe_topic"] = "emqx/esp8266";
    //   // 发布主题
    //   mqttConf["mqtt_publish_topic"] = "emqx/esp8266";
    //   // 用户名
    //   mqttConf["mqtt_username"] = "test";
    //   // 密码
    //   mqttConf["mqtt_password"] = "test123456";
    //  // NTP Server settings
    //   mqttConf["ntp_server"] = "pool.ntp.org";// Recommended NTP server for users in China
    //   mqttConf["gmt_offset_sec"] = 0; // GMT offset in seconds (adjust for your time zone)
    //   mqttConf["daylight_offset_sec"] = 0;// Daylight saving time offset in seconds
    //   // 每间隔多少秒发布一次当前状态
    //   mqttConf["push_state_m"] = 20;
    //   // SSL certificate for MQTT broker
    // // Load DigiCert Global Root G2, which is used by EMQX Public Broker: broker.emqx.io
    // // static const char ca_cert[]
    // // PROGMEM = R"EOF()EOF";
    //   // 服务端的 ssl/tls ca证书
    //   mqttConf["ca_cert"] = R"EOF(
    // -----BEGIN CERTIFICATE-----
    // MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
    // CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
    // -----END CERTIFICATE-----
    // )EOF";

    }
    void initConfig() {
      // initWifiConfig();
      initMqttConfig();
    }
    void tickerAdd() {
     tickerCount++;
    }
    void setup() {
      // Serial.begin(115200);
      Serial.println("MQTT setup");
      initConfig();
      pinMode(LED_BUILTIN, OUTPUT);  // 这里换成变量
      pinMode(pin, OUTPUT);
      digitalWrite(pin, LOW);  // GPIO0 低电平，吸合继电器，作为初始状态

      // Ticker定时对象
      // ticker.attach(1, tickerAdd);
      //设置ESP8266工作模式为无线终端模式
      // WiFi.mode(WIFI_STA);
      // 已移植 独立类文件
      // connectToWiFi();
      // syncTime();  // X.509 validation requires synchronization time
      mqtt_client.setServer((const char *)mqttConf["mqtt_broker"], (const int)mqttConf["mqtt_port"]);
      mqtt_client.setCallback([this](char *topic, byte *payload, unsigned int length) { this->mqttCallback(topic, payload,length); });
      // connectToMQTT();
    }
    void syncTime() {
      configTime((const long)mqttConf["gmt_offset_sec"], (const int)mqttConf["daylight_offset_sec"], (const char *)mqttConf["ntp_server"]);
      Serial.print("Waiting for NTP time sync: ");
      while (time(nullptr) < 8 * 3600 * 2) {
        delay(1000);
        Serial.print(".");
      }
      Serial.println("Time synchronized");
      struct tm timeinfo;
      if (getLocalTime(&timeinfo)) {
        Serial.print("Current time: ");
        Serial.println(asctime(&timeinfo));
      } else {
        Serial.println("Failed to obtain local time");
      }
    }
    void connectToWiFi() {
      // WiFi.begin((const char *)wifiConf["user"], (const char *)wifiConf["password"]);
      while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("MQTT Connecting to WiFi...");
      }
      Serial.println("MQTT Connected to WiFi");
    }

    void connectToMQTT() {
      BearSSL::X509List serverTrustedCA((const char *)mqttConf["ca_cert"]);
      espClient.setTrustAnchors(&serverTrustedCA);
      JSONVar mqttMsg;
      while (!mqtt_client.connected()) {
        // String client_id = "esp8266-client-" + String(WiFi.macAddress());
        mqttMsg["client_id"] = "esp8266-client-" + String(WiFi.macAddress());
        Serial.printf("Connecting to MQTT Broker as %s.....\n", ((String)mqttMsg["client_id"]).c_str());
        if (mqtt_client.connect(((String)mqttMsg["client_id"]).c_str(), (const char *)mqttConf["mqtt_username"], (const char *)mqttConf["mqtt_password"])) {
          Serial.println("Connected to MQTT broker");
          mqttMsg["msg"] = "Hi EMQX I'm ESP8266";
          mqttMsg["key"] = "connect";
          mqtt_client.subscribe((const char *)mqttConf["mqtt_subscribe_topic"]);
          // Publish message upon successful connection
          // 将 JSON 对象转换为字符串
          String jsonString = JSON.stringify(mqttMsg);
          mqtt_client.publish((const char *)mqttConf["mqtt_publish_topic"], jsonString.c_str());
          // doCallback(0);
        } else {
          // conErrCount++;
          char err_buf[128];
          espClient.getLastSSLError(err_buf, sizeof(err_buf));
          Serial.print("Failed to connect to MQTT broker, rc=");
          
          Serial.println(mqtt_client.state());
          Serial.print("SSL error: ");
          // String jsonString2 = JSON.stringify(mqttConf);
          // Serial.println(jsonString2);
          Serial.println(err_buf);
          // doCallback(conErrCount);
          delay(5000);
        }
      }
    }
    // 发布上报针脚状态信息
    void pubMQTTmsg() {
      JSONVar mqttMsg;
      // 建立发布主题。
      // 定时向服务器主题发布当前GPIO0引脚状态
      String state;
      if (digitalRead(0)) {
        mqttMsg["state"] = false;  // 高电平断开继电器
      } else {
        mqttMsg["state"] = true;  // 低电平吸合继电器
      }
      String jsonString = JSON.stringify(mqttMsg);

      // 实现ESP8266向主题发布信息
      if (mqtt_client.publish((const char *)mqttConf["mqtt_publish_topic"], jsonString.c_str())) {
        Serial.print("Publish Topic: ");
        Serial.println((const char *)mqttConf["mqtt_publish_topic"]);
        Serial.print("Publish message: ");
        Serial.println(jsonString.c_str());
      } else {
        Serial.println("Message Publish Failed.");
      }
    }
    // Callback callback = nullptr;
    //  // 函数指针类型定义
    // typedef void (MyMqtt::*Callback)();
    void mqttCallback(char *topic, byte *payload, unsigned int length) {
      Serial.print("Message received on topic: ");
      Serial.print(topic);
      Serial.print("]: ");
      // 将获取到的pyte类payload消息转换为String类型的data
      String jsonString = "";
      for (int i = 0; i < length; i++) {
        jsonString = jsonString + (char)payload[i];
      }
      Serial.println(jsonString);
      // mqttRes=
      // 解析 JSON 字符串
      JSONVar parsed = JSON.parse(jsonString);

      if (JSON.typeof(parsed) == "undefined") {
        Serial.println("Parsing failed!");
        return;
      }
      if (parsed["switch"] != null) {
        Serial.println((String)parsed["switch"]);
        if ((String)parsed["switch"] == "1") {  // 如果收到的信息为"1"，注意双引号为String，单引号为char
          digitalWrite(LED_BUILTIN, LOW);  // 则点亮LED。
          digitalWrite(pin, LOW);               // GPIO0 低电平，吸合继电器
        } else {
          digitalWrite(LED_BUILTIN, HIGH); // 否则熄灭LED。
          digitalWrite(pin, HIGH);  // GPIO0 高电平，断开继电器
        }
      }
    }

    // 状态持续函数，一直重复执行
    void startloop() {
        if (!mqtt_client.connected()) {
        // 建立链接
        // connectToMQTT();
      initMqttConfig();
      String jsonString = JSON.stringify(mqttConf);
      Serial.println(jsonString);
          delay(10000);
      } else {
        // 每隔3秒钟发布一次信息，一般用于状态报告
        if (mqttConf["push_state_m"] && tickerCount >= (int)mqttConf["push_state_m"]) {
          pubMQTTmsg();
          tickerCount = 0;
        }
        //  心跳
        mqtt_client.loop();
      }
    }
    private:
    int conErrCount;
    Callback callback_;
};
// 使用
// 服务端向订阅主题发布 消息内容 {"switch": "1"} 1是开灯，否则是关灯
#endif